#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <gmp.h>
#include <time.h>

int GaussLegendre()
{
	double FinalTime;
	int NumInter = 0;	// Contagem de Numero de Interacoes para calcular o numero Pi

	/* 10 000 000 * log2(10) 
	Precisao minima para calcular a precisao de 10 milhoes de 
	digitos				*/
		     
	mpf_set_default_prec(33219280);

	/*Declaracao de Variaveis mpf_t para precisao float da biblioteca GMP*/

	mpf_t a;
	mpf_t b;
	mpf_t t;
	mpf_t p;
    	mpf_t scratch;
	mpf_t pi0;

	mpf_t a1;	
	mpf_t b1;
	mpf_t t1;
	mpf_t p1;
	mpf_t pi;


	/* Inicializacao de Variaveis */
	
	mpf_init (a);
	mpf_init (b);
	mpf_init (t);
	mpf_init (p);

	mpf_init (a1);	
	mpf_init (b1);
	mpf_init (t1);
	mpf_init (p1);
	
	mpf_init (pi0);
	mpf_init (pi);
    	mpf_init(scratch);

	/* Condicoes Iniciais */
	mpf_init_set_ui(a, 1);
	mpf_init_set_ui(p, 1);
	mpf_init_set_ui(pi,0);
	mpf_init_set_ui(pi,1);

	/* b = 1/sqrt(2)     */

	mpf_sqrt_ui(b,2);
	mpf_ui_div(b,1,b);
	
	/* t = 1/4 	     */
	mpf_init_set_ui(t, 1);
	mpf_div_ui(t,t,4);

	clock_t start = clock();

	// Enquanto a precisao do numero pi nao variar da sua precisao anterior
	while(mpf_cmp(pi0,pi)!=0)	
	{		
		mpf_set(pi0,pi);	//atualiza o pi anterior

		//a1 = (a + b)/2;
		mpf_add(a1,a,b);
		mpf_div_ui(a1,a1,2);

		// b1 = sqrt(a*b);
		mpf_mul(b1,a,b);		
		mpf_sqrt(b1,b1);

		//t1 = t - ( p*((a - a1)*(a - a1)) );
		mpf_sub(scratch, a, a1);
        	mpf_pow_ui(scratch, scratch, 2);
		mpf_mul(scratch,scratch,p);
        	mpf_sub(t1, t, scratch);

		//p1 = 2*p;
		mpf_mul_ui(p1, p, 2);
	
		// pi := ((a + b)**2) / 4t
		mpf_add(pi, a1, b1);
		mpf_pow_ui(pi, pi, 2);
		mpf_mul_ui(scratch, t1, 4);	
		mpf_div(pi, pi, scratch);

		/* Atualizacao de Variaveis */
		mpf_set(a, a1);
        	mpf_set(b, b1);
		mpf_set(t,t1);
		mpf_set(p,p1);
		
		NumInter++;	
	}
	FinalTime = (((double)clock()-start)/CLOCKS_PER_SEC);
	gmp_printf("pi = %.10000000Ff\n",pi);
	printf("Numero de interacoes count = %d\n",NumInter);
	printf("Tempo total: %f\n",FinalTime);
 	/* Libera memoria utilizada */
 	mpf_clears(a,b,t,p,a1,b1,t1,p1,pi0,pi,NULL);
}

int main(int argc,char *argv[])
{
	GaussLegendre();
	return 1;
} 
